package com.touzhijia.authority.security;

import com.touzhijia.authority.domain.entity.Permission;
import com.touzhijia.authority.domain.entity.WebPermission;
import com.touzhijia.authority.domain.model.WebPermissionDto;
import com.touzhijia.authority.mapper.PermissionMapper;
import com.touzhijia.authority.mapper.WebPermissionMapper;
import com.touzhijia.authority.service.WebPermissionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.*;

/**
 * 初始化系统的所有Url权限
 * <p>
 * 作者： lzw<br/>
 * 创建时间：2018-03-17 11:24 <br/>
 */
@Service
@Slf4j
public class InitSystemUrlPermission implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private SecurityConfig securityConfig;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private WebPermissionMapper webPermissionMapper;
    @Autowired
    private WebPermissionService webPermissionService;

    @SuppressWarnings("deprecation")
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (StringUtils.isBlank(securityConfig.getModuleName())) {
            throw new RuntimeException("系统名称未配置");
        }
        // 获取系统中所有的资源,并排序 - allPermission
        List<WebPermissionDto> allPermission = new ArrayList<>();
        RequestMappingHandlerMapping handlerMapping = event.getApplicationContext().getBean(RequestMappingHandlerMapping.class);
        Map<RequestMappingInfo, HandlerMethod> handlerMap = handlerMapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMap.entrySet()) {
            RequestMappingInfo requestMappingInfo = entry.getKey();
            HandlerMethod handlerMethod = entry.getValue();
            // 获取URL路由信息
            allPermission.add(newPermissions(requestMappingInfo, handlerMethod));
        }
        Collections.sort(allPermission);
        // 加载当前模块所有的权限信息 - moduleAllPermission
        List<WebPermissionDto> moduleAllPermission = webPermissionMapper.findUrlPermissionByModule(securityConfig.getModuleName());
        // 保存系统中有而数据库里没有的资源 - addPermission
        List<WebPermissionDto> addPermission = addPermission(allPermission, moduleAllPermission);
        // 统计数据库中有而系统中没有的资源数据 - notExistPermission
        moduleAllPermission = webPermissionMapper.findUrlPermissionByModule(securityConfig.getModuleName());
        List<WebPermissionDto> notExistPermission = getNotExistPermission(allPermission, moduleAllPermission);
        // 打印相应的日志
        if (log.isInfoEnabled()) {
            StringBuilder strTmp = new StringBuilder();
            strTmp.append("\r\n");
            strTmp.append("#=======================================================================================================================#\r\n");
            strTmp.append("# 新增的权限配置如下(").append(addPermission.size()).append("条):\r\n");
            for (WebPermissionDto permission : addPermission) {
                strTmp.append("#\t ").append(getPermissionStr(permission)).append("\r\n");
            }
            strTmp.append("# 数据库里无效的权限配置(").append(notExistPermission.size()).append("条):\r\n");
            for (WebPermissionDto permission : notExistPermission) {
                strTmp.append("#\t ").append(getPermissionStr(permission)).append("\r\n");
            }
            strTmp.append("#=======================================================================================================================#");
            log.info(strTmp.toString());
        }
    }

    /**
     * 打印权限配置信息字符串
     */
    private String getPermissionStr(WebPermissionDto permission) {
        return String.format("| %1$s | [%2$s] [%3$s#%4$s] -> [%5$s]",
                permission.getModule(),
                permission.getTitle(),
                permission.getControllerClass(),
                permission.getControllerMethod(),
                permission.getResourcesUrl());
    }

    /**
     * 统计数据库中有而系统中没有的资源数据
     *
     * @param allPermission       当前模块所有权限
     * @param moduleAllPermission 数据库中当前模块所有的权限信息
     * @return 数据库中有而系统中没有的资源数据
     */
    @Transactional
    protected List<WebPermissionDto> getNotExistPermission(List<WebPermissionDto> allPermission, List<WebPermissionDto> moduleAllPermission) {
        List<WebPermissionDto> notExistPermission = new ArrayList<>();
        Map<String, WebPermissionDto> mapPermission = new HashMap<>();
        // module controllerClass controllerMethod controllerMethodParams
        String format = "%1$-128s|%2$-255s|%3$-255s|%4$-255s";
        for (WebPermissionDto permission : allPermission) {
            mapPermission.put(String.format(format,
                    permission.getModule(),
                    permission.getControllerClass(),
                    permission.getControllerMethod(),
                    permission.getControllerMethodParams()), permission);
        }
        for (WebPermissionDto dbPermission : moduleAllPermission) {
            String key = String.format(format,
                    dbPermission.getModule(),
                    dbPermission.getControllerClass(),
                    dbPermission.getControllerMethod(),
                    dbPermission.getControllerMethodParams());
            WebPermissionDto permission = mapPermission.get(key);
            if (permission == null) {
                // 数据库里有 系统中没有 - 更新 controllerExist
                if (!Objects.equals(dbPermission.getControllerExist(), WebPermission.Controller_Exist_0)) {
                    WebPermission update = new WebPermission();
                    update.setId(dbPermission.getWebPermissionId());
                    update.setControllerExist(WebPermission.Controller_Exist_0);
                    update.setUpdateAt(new Date());
                    webPermissionMapper.updateByPrimaryKeySelective(update);
                }
                notExistPermission.add(dbPermission);
            } else {
                // 数据库里有 系统中也有 - 更新 resourcesUrl
                if (!Objects.equals(permission.getResourcesUrl(), dbPermission.getResourcesUrl())) {
                    WebPermission update = new WebPermission();
                    update.setId(dbPermission.getPermissionId());
                    update.setResourcesUrl(permission.getResourcesUrl());
                    webPermissionMapper.updateByPrimaryKeySelective(update);
                }
                if (!Objects.equals(permission.getTitle(), dbPermission.getTitle())) {
                    Permission update = new Permission();
                    update.setId(dbPermission.getPermissionId());
                    update.setTitle(permission.getTitle());
                    update.setUpdateAt(new Date());
                    permissionMapper.updateByPrimaryKeySelective(update);
                }
            }
        }
        return notExistPermission;
    }

    /**
     * 保存所有新增的权限 (module controllerClass controllerMethod resourcesUrl)
     *
     * @param allPermission       当前模块所有权限
     * @param moduleAllPermission 数据库中当前模块所有的权限信息
     * @return 新增的权限
     */
    @Transactional
    protected List<WebPermissionDto> addPermission(List<WebPermissionDto> allPermission, List<WebPermissionDto> moduleAllPermission) {
        List<WebPermissionDto> addPermission = new ArrayList<>();
        Set<String> setPermission = new HashSet<>();
        // module controllerClass controllerMethod controllerMethodParams
        String format = "%1$-128s|%2$-255s|%3$-255s|%4$-255s";
        for (WebPermissionDto permission : moduleAllPermission) {
            setPermission.add(String.format(format,
                    permission.getModule(),
                    permission.getControllerClass(),
                    permission.getControllerMethod(),
                    permission.getControllerMethodParams()));
        }
        for (WebPermissionDto permission : allPermission) {
            String key = String.format(format,
                    permission.getModule(),
                    permission.getControllerClass(),
                    permission.getControllerMethod(),
                    permission.getControllerMethodParams());
            if (!setPermission.contains(key)) {
                // 新增不存在的权限配置
                webPermissionService.saveWebPermission(permission);
                addPermission.add(permission);
            }
        }
        return addPermission;
    }

    /**
     * 创建一个 Permission
     */
    @SuppressWarnings("deprecation")
    private WebPermissionDto newPermissions(RequestMappingInfo requestMappingInfo, HandlerMethod handlerMethod) {
        // 提取MVC路由信息
        Class<?> beanType = handlerMethod.getBeanType();
        Method method = handlerMethod.getMethod();
        // 获取标题 - Swagger2注解
        StringBuilder title = new StringBuilder();
        Api api = beanType.getAnnotation(Api.class);
        if (api != null && (StringUtils.isNotBlank(api.value()) || StringUtils.isNotBlank(api.description()))) {
            title.append("[").append(StringUtils.isNotBlank(api.value()) ? api.value() : api.description()).append("]");
        } else {
            title.append("[").append(beanType.getSimpleName()).append("]");
        }
        ApiOperation apiOperation = handlerMethod.getMethodAnnotation(ApiOperation.class);
        if (apiOperation != null && StringUtils.isNotBlank(apiOperation.value())) {
            title.append("-").append(apiOperation.value());
        } else {
            title.append("-").append(method.getName());
        }
        // 获取放签名
        StringBuilder methodParams = new StringBuilder();
        Class<?>[] paramTypes = method.getParameterTypes();
        for (Class<?> clzz : paramTypes) {
            if (methodParams.length() > 0) {
                methodParams.append(", ");
            }
            methodParams.append(clzz.getName());
        }
        // 请求Url
        StringBuilder resourcesUrl = new StringBuilder();
        Set<String> urlArray = requestMappingInfo.getPatternsCondition().getPatterns();
        for (String url : urlArray) {
            if (resourcesUrl.length() > 0) {
                resourcesUrl.append(" | ");
            }
            resourcesUrl.append(url);
        }
        // 构建权限信息
        WebPermissionDto permission = new WebPermissionDto();
        permission.setModule(securityConfig.getModuleName());
        permission.setPermission(UUID.randomUUID().toString());
        if (securityConfig.getDefaultNeedAuthorization() != null && securityConfig.getDefaultNeedAuthorization()) {
            permission.setNeedAuthorization(WebPermission.Need_Authorization_1);
        } else {
            permission.setNeedAuthorization(WebPermission.Need_Authorization_2);
        }
        permission.setResourcesType(Permission.Resources_Type_1);
        permission.setTitle(title.toString());
        permission.setControllerClass(beanType.getName());
        permission.setControllerMethod(method.getName());
        permission.setControllerMethodParams(methodParams.toString());
        permission.setResourcesUrl(resourcesUrl.toString());
        permission.setControllerExist(WebPermission.Controller_Exist_1);
        permission.setDescription("系统自动生成的权限配置");
        permission.setCreateAt(new Date());
        return permission;
    }
}
